/*
    函数的基本语法：
    返回值类型 ：一个函数可以返回一个值。在函数定义中
    函数名：给函数起个名称
    参数列表：使用该函数时，传入的数据
    函数体语句：花括号内的代码，函数内需要执行的语句
    return表达式： 和返回值类型挂钩，函数执行完后，返回相应的数据
*/
#include <iostream>
using namespace std;

// 函数的参数传递 ==========================

// 值传递 :传递的是实参的副本，修改副本不会影响实参
// 引用传递 :传递的是实参的地址，修改实参会影响副本
// 指针传递 :传递的是实参的地址，修改实参会影响副本

void func1(int a) {}
void func2(int &a) {}
void func3(int *a) {}

// 函数的返回值 ===============================

//- 函数的返回值类型在定义时指定。
//- 返回值可以是任何数据类型，包括自定义类型。
//- 函数的返回值可以赋值给变量或用于表达式中。

// 函数的声明和定义=========================
/*
    - 可以多次声明同一个函数，但只能定义一次。
    - 同一个函数名可以有多个不同的参数列表。
    - 使用函数之前，必须先定义函数。
    - 函数的声明和定义可以分开写，也可以声明的同时定义。

    - 声明和定义可以分文件编写：头文件声明、源文件定义（实现）


*/

// 函数的重载==========================

//  函数重载要求参数列表不同，返回类型可以相同也可以不同。
//  参数列表的不同可以是参数类型不同、参数数量不同或参数顺序不同。
void func4(int x)
{
    // 函数体
}

void func4(double x)
{
    // 函数体
}

// 函数的默认参数====================

void func5(int x = 10)
{
    // 函数体，此时x默认值为10
}

// 函数的内联=============================

/*
    内联函数定义必须在使用之前
    编译器有权决定是否内联
    内联不适合大型函数，会代码膨胀
    内联函数不能包含循环或递归（编译器可能会优化掉、递归是肯定不行的）
*/

// 内联函数的作用类似于宏定义。只不过还是有一些区别的。（op）

inline int func6(int x, int y) { return x + y; }
void func7(int a, int b) { func6(a, b); }

// 函数的递归 =============================

// 自己调用自己，直到条件满足。
// 递归函数必须有明确的出口，否则会导致栈溢出。
// 可能会导致栈溢出，所以要慎用。
int func8(int n)
{
    if (n == 1)
    {
        return 1;
    }
    else
    {
        return n * func8(n - 1);
    }
}

// 函数指针 ============================

// 函数指针是C++ 中一种强大的工具，它允许将函数作为参数传递给其他函数，实现回调函数等功能。
//  定义方式：data_types (*func_pointer)( data_types arg1, data_types arg2, ...,data_types argn);

// 函数指针不能偏移

// 这是一个函数
int add(int a, int b) { return a + b; }

void funcp()
{
    // 这里就是一个函数指针， 这个指针指向了之前定义的add 函数，并且这个指针的名字为p
    int (*Paa)(int, int) = add;
    int (*Pbb)(int, int) = &add;
    // 这两种方式都可以，但是第二种方式可以避免偏移

    // 这里就是 调用了这个指针，然后指针指向了函数的地址，并且传递了两个参数
    int a = Paa(1, 2); // a = 3
}

// 指针函数

// 返回值是指针的函数
int *func9(int a)
{
    int *p = new int(a);
    return p;
}

// 函数模板 ==================
// 函数模板是C++ 中一种非常强大的特性，它允许定义一个函数，使其可以接受不同的数据类型。

template <typename T>
T add(T a, T b)
{
    return a + b;
}

// 函数模板的使用
void func10()
{
    int a = add<int>(1, 2);           // a = 3
    double b = add<double>(1.5, 2.5); // b = 4.0
}

// 函数内参数作用域 =====================

// 在函数中可以访问： 局部变量、全局变量、静态变量

//================================函数的高级特性  之后再说吧 QAQ